package com.c.util;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Arrays;

import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.namedparam.BeanPropertySqlParameterSource;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;

/**
 * 封装jdbcTemplate,通过NamedParameterJdbcTemplate直接保存或者更新对象<一句话功能简述><功能详细描述>
 * 
 * @author wuchenyang
 * @version [版本号, 2018年8月9日]
 */
@SuppressWarnings("rawtypes")
public class DbUtils {

	/**
	 * 保存一个对象到对应数据库表，表中参数为下划线形式，对象变量为驼峰形式
	 * 
	 * @param jdbcTemplate
	 * @param tableName
	 * @param object
	 *            要保存的对象
	 */
	public static void save(String tableName, Object object) {
		JdbcTemplate jdbcTemplate = SpringUtils.getApplicationContext().getBean("jdbcTemplate", JdbcTemplate.class);
		NamedParameterJdbcTemplate namedParameterJdbcTemplate = new NamedParameterJdbcTemplate(jdbcTemplate);
		String insertSql = "insert into " + tableName + insertSqlParams(object.getClass());
		namedParameterJdbcTemplate.update(insertSql, new BeanPropertySqlParameterSource(object));
	}

	/**
	 * 更新一个数据库对象到对应数据库表，表中参数为下划线形式，对象变量为驼峰形式
	 * 
	 * @param jdbcTemplate
	 * @param tableName
	 * @param object
	 *            要更新的对象
	 * @param where
	 *            update语句的where 条件部分
	 */
	public static void update(String tableName, Object object, String where) {
		JdbcTemplate jdbcTemplate = SpringUtils.getApplicationContext().getBean("jdbcTemplate", JdbcTemplate.class);
		NamedParameterJdbcTemplate namedParameterJdbcTemplate = new NamedParameterJdbcTemplate(jdbcTemplate);
		String updateSql = "update " + tableName + " set " + updateSqlParams(object.getClass()) + "  " + where;
		namedParameterJdbcTemplate.update(updateSql, new BeanPropertySqlParameterSource(object));
	}

	/**
	 * 通过反射获取当前类和父类的成员变量，组成sql语句的变量<一句话功能简述><功能详细描述>
	 *
	 * @param clz
	 * @return
	 */
	@SuppressWarnings("unchecked")
	private static String updateSqlParams(Class clz) {
		StringBuilder stringBuilder = new StringBuilder();
		ArrayList<Field> fieldArray = new ArrayList(Arrays.asList(clz.getDeclaredFields()));
		if (clz.getSuperclass() != null) {
			Field[] arrayOfField = clz.getSuperclass().getDeclaredFields();
			for (Field field : arrayOfField) {
				fieldArray.add(field);
			}
		}
		for (int i = 0; i < fieldArray.size(); i++) {
			Field field = fieldArray.get(i);
			// 不要更新的字段
			if (field.getName().indexOf("serialVersionUID") > -1 || field.getName().indexOf("createAccount") > -1
					|| field.getName().indexOf("createTime") > -1) {
				continue;
			}
			stringBuilder.append("," + toUnderlineCase(field.getName()).replace(" ", "") + "= :" + field.getName());
		}
		return stringBuilder.toString().substring(1).replace(" ", "");
	}

	/**
	 * 通过反射获取当前类和父类的成员变量，组成sql语句的变量<一句话功能简述><功能详细描述>
	 *
	 * @param clz
	 * @return
	 */
	@SuppressWarnings("unchecked")
	private static String insertSqlParams(Class clz) {
		StringBuilder stringBuilder1 = new StringBuilder();
		StringBuilder stringBuilder2 = new StringBuilder();
		ArrayList<Field> fieldArray = new ArrayList(Arrays.asList(clz.getDeclaredFields()));
		if (clz.getSuperclass() != null) {
			Field[] arrayOfField = clz.getSuperclass().getDeclaredFields();
			for (Field field : arrayOfField) {
				fieldArray.add(field);
			}
		}
		for (int i = 0; i < fieldArray.size(); i++) {
			Field field = fieldArray.get(i);
			if (field.getName().indexOf("serialVersionUID") > -1 || field.getName().indexOf("modifyAccount") > -1
					|| field.getName().indexOf("modifyTime") > -1) {
				continue;
			}
			stringBuilder1.append(",:" + field.getName());
			stringBuilder2.append("," + toUnderlineCase(field.getName()));
		}
		return " (" + stringBuilder2.toString().substring(1).replace(" ", "") + ") values ("
				+ stringBuilder1.toString().substring(1).replace(" ", "") + ")";
	}

	public static final String UNDERLINE = "_";

	/**
	 * 将驼峰式命名的字符串转换为下划线方式。如果转换前的驼峰式命名的字符串为空，则返回空字符串。<br>
	 * 例如：HelloWorld=》hello_world
	 *
	 * @param camelCaseStr
	 *            转换前的驼峰式命名的字符串
	 * @return 转换后下划线大写方式命名的字符串
	 */
	public static String toUnderlineCase(CharSequence camelCaseStr) {
		if (camelCaseStr == null) {
			return null;
		}
		final int length = camelCaseStr.length();
		StringBuilder sb = new StringBuilder();
		char c;
		boolean isPreUpperCase = false;
		for (int i = 0; i < length; i++) {
			c = camelCaseStr.charAt(i);
			boolean isNextUpperCase = true;
			if (i < (length - 1)) {
				isNextUpperCase = Character.isUpperCase(camelCaseStr.charAt(i + 1));
			}
			if (Character.isUpperCase(c)) {
				if (!isPreUpperCase || !isNextUpperCase) {
					if (i > 0) {
						sb.append(UNDERLINE);
					}
				}
				isPreUpperCase = true;
			} else {
				isPreUpperCase = false;
			}
			sb.append(Character.toLowerCase(c));
		}
		return sb.toString().replace(" ", "");
	}

	/**
	 * 将下划线方式命名的字符串转换为驼峰式。如果转换前的下划线大写方式命名的字符串为空，则返回空字符串。<br>
	 * 例如：hello_world=》helloWorld
	 *
	 * @param name
	 *            转换前的下划线大写方式命名的字符串
	 * @return 转换后的驼峰式命名的字符串
	 */
	public static String toCamelCase(CharSequence name) {
		if (null == name) {
			return null;
		}
		String name2 = name.toString();
		if (name2.contains(UNDERLINE)) {
			name2 = name2.toLowerCase();
			StringBuilder sb = new StringBuilder(name2.length());
			boolean upperCase = false;
			for (int i = 0; i < name2.length(); i++) {
				char c = name2.charAt(i);
				if (c == '_') {
					upperCase = true;
				} else if (upperCase) {
					sb.append(Character.toUpperCase(c));
					upperCase = false;
				} else {
					sb.append(c);
				}
			}
			return sb.toString().replace(" ", "");
		} else {
			return name2.replace(" ", "");
		}
	}
}
